package org.demo.treeeditor.mode;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.demo.treeeditor.Node;
import org.demo.treeeditor.StateMachine;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

public class BaseMode extends AbstractMode {


	public BaseMode(StateMachine stateMachine) {
		super(stateMachine);

	}

	@Override
	public void init() {
		setAction("E","movePrevious");
		setAction("D","moveNext");
		setAction("F","expendCollapse");
		setAction("S","moveToParent");
		
		setAction("I","movePrevious");
		setAction("K","moveNext");
		setAction("J","expendCollapse");
		setAction("L","moveToParent");


		setAction(33,"zoomIn");
		setAction(34,"zoomOut");
		//setAction("L","moveToFirstChild");
		setAction("J","expendCollapse");

		setAction("A","appendChild");
		setAction("T","remove");
		setAction("C","cut");
		setAction("B","save");
		setAction("Y","load");
		setAction("V","pasteAfter");
		setAction("G","pasteAsChild");
		setAction(32,"editMode");
		setAction(0,"debug");

	}


	void editMode(){
		stateMachine.getTextPrompt().editElement(stateMachine.getCurrentNode().getNameContainerVisualElement());
		stateMachine.setState(StateMachine.StateEnum.edit);
	}

	void save(){
		Document doc = createEmptyDocument();
		org.w3c.dom.Node root = stateMachine.getRootNode().toXml(doc);
		doc.appendChild((Element)root);
		saveDocument(doc,"file.xml");
	}

	void load(){
		Document doc = loadFile("file.xml");
		removeEmptyText(doc.getDocumentElement());
		stateMachine.getRootNode().clear();
		stateMachine.getRootNode().fromXml(doc.getDocumentElement());
		stateMachine.getBoxLayoutEngine().reLayout();
		stateMachine.setCurrentNode(stateMachine.getRootNode());
	}

	static void removeEmptyText(Element elem){
		//NodeList childs = elem.getChildNodes();
		org.w3c.dom.Node node = elem.getFirstChild();
		while(node!=null){
			if(node.getNodeType()==org.w3c.dom.Node.TEXT_NODE&&node.getNodeValue()!=null&&node.getNodeValue().matches("\\A[ \n\t\b]*\\Z")){
				org.w3c.dom.Node nodeToRemove = node;
				node = node.getNextSibling();
				elem.removeChild(nodeToRemove);
			}else if(node.getNodeType()==org.w3c.dom.Node.ELEMENT_NODE){
				removeEmptyText((Element)node);
				node = node.getNextSibling();
			}else{
				node = node.getNextSibling();
			}

		}


	}

	public static Document loadFile(String fileName){
		Document result = null;
		try{
			DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance();
			DocumentBuilder constructeur = fabrique.newDocumentBuilder();
			File xml = new File(fileName);
			result = constructeur.parse(xml); 
			//removeEmptyText(result.getDocumentElement());
		}catch(ParserConfigurationException pce){
			pce.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return  result;
	}


	public static Document createEmptyDocument(/*String rootElementName*/){
		DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance();
		DocumentBuilder constructeur = null;
		try {
			constructeur = fabrique.newDocumentBuilder();
		} catch (ParserConfigurationException e1) {
			e1.printStackTrace();
		}
		Document currentDocument = constructeur.newDocument();
		//currentDocument.appendChild(currentDocument.createElement(rootElementName)); 
		return currentDocument;
	}



	public static void saveDocument(Document doc,String fileName){
		try {
			Source source = new DOMSource(doc);
			File file = new File(fileName);
			Result result = new StreamResult(file);
			Transformer transformer = TransformerFactory.newInstance().newTransformer();
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			//transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
			//transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
			transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
			transformer.transform(source, result);
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}
	}

	void movePrevious(){
		System.out.println("movePrevious was pressed");
		Node current = stateMachine.getCurrentNode();
		Node previousNode = current.getPreviousSibling();
		if(previousNode!=null){
			stateMachine.setCurrentNode(previousNode);
		}else{
			System.out.println("no previous node");
		}
	}

	void moveNext(){
		System.out.println("moveNext was pressed");
		Node current = stateMachine.getCurrentNode();
		Node nextNode = current.getNextSibling();
		if(nextNode!=null){
			stateMachine.setCurrentNode(nextNode);
		}else{
			System.out.println("no next node");
		}
	}


	void moveToFirstChild(){
		moveToChild(0);
	}

	void moveToLastChild(){
		Integer index = stateMachine.getCurrentNode().getChilds().size()-1;
		if(index>-1){
			moveToChild(index);
		}
	}

	void moveToChild(Integer index){
		System.out.println("moveToChild was pressed");
		Node current = stateMachine.getCurrentNode();
		Node nextNode = current.getChild(index);
		if(nextNode!=null){
			stateMachine.setCurrentNode(nextNode);
		}else{
			System.out.println("no next node");
		}	
	}


	void moveToParent(){
		System.out.println("moveToParent was pressed");
		Node current = stateMachine.getCurrentNode();
		Node parent = (Node)current.getParent();
		if(parent!=null){
			stateMachine.setCurrentNode(parent);
		}else{
			System.out.println("no parent node");
		}
	}

	void expendCollapse(){
		stateMachine.getCurrentNode().expendCollapse();
	}

	void appendChild(){
		System.out.println("appendChild was pressed");
		Node current = stateMachine.getCurrentNode();
		current.expand();
		Node newNode = new Node(stateMachine.getBoxLayoutEngine());
		//NodeFactory.getInstance().createNode();
		newNode.setText("|");
		current.appendChild(newNode);
		stateMachine.getBoxLayoutEngine().reLayout();
		moveToLastChild();
		editMode();
		stateMachine.getTextPrompt().backSpace();
	}

	Node remove(){
		System.out.println("remove was pressed");
		Node current = stateMachine.getCurrentNode();
		Node parent = current.getParent();
		Node next = current.getNextBrother();
		Node previous = current.getPreviousBrother();		
		if(next!=null||previous!=null||parent!=null){
			current.getParent().remove(current);
			stateMachine.getBoxLayoutEngine().reLayout();
			if(next!=null){
				stateMachine.setCurrentNode(next);
			}else if (previous!=null){
				stateMachine.setCurrentNode(previous);
			}else if (parent!=null){
				stateMachine.setCurrentNode(parent);
			}
		}
		return current;
	}

	void cut(){
		stateMachine.setBufferedNode(remove());
	}

	void pasteAfter(){
		paste(false);
	}

	void pasteAsChild(){
		paste(true);
	}

	void paste(Boolean asChild){
		Node bufferedNode = stateMachine.getBufferedNode();
		if(bufferedNode!=null){
			if(asChild){
				stateMachine.getCurrentNode().appendChild(bufferedNode);
			}else{
				Node parent = stateMachine.getCurrentNode().getParent();
				if(parent!=null){
					parent.insertBefore(stateMachine.getCurrentNode().getNextBrother(), bufferedNode);
				}
			}			
			stateMachine.getBoxLayoutEngine().reLayout();
			stateMachine.setCurrentNode(bufferedNode);
			stateMachine.setBufferedNode(null);
		}
	}


	void debug(){
		System.out.println("debug was pressed");
		System.out.println(stateMachine.getBoxLayoutEngine().getRootElement().serializeToText(""));
	}

	void zoomIn(){
		stateMachine.getBoxLayoutEngine().getCamera().moveZ(-4.0f);
	}

	void zoomOut(){
		stateMachine.getBoxLayoutEngine().getCamera().moveZ(4.0f);
	}



}
